﻿Imports System.Runtime.InteropServices
Imports System.IO

Friend Module mMirMapFile

    <StructLayout(LayoutKind.Explicit, Size:=14)> _
    Public Structure RawSmallTile
        <FieldOffset(0)> <MarshalAs(UnmanagedType.I1)> Dim passable As Byte '2= blocked 3= passable
        <FieldOffset(1)> <MarshalAs(UnmanagedType.I1)> Dim Data1 As Byte
        <FieldOffset(2)> <MarshalAs(UnmanagedType.I1)> Dim Data2 As Byte
        <FieldOffset(3)> <MarshalAs(UnmanagedType.I1)> Dim TopSet As Byte
        <FieldOffset(4)> <MarshalAs(UnmanagedType.I1)> Dim BottomSet As Byte
        <FieldOffset(5)> <MarshalAs(UnmanagedType.I2)> Dim BottomTile As UInt16
        <FieldOffset(7)> <MarshalAs(UnmanagedType.I2)> Dim TopTile As UInt16
        <FieldOffset(9)> <MarshalAs(UnmanagedType.I1)> Dim Data3 As Byte
        <FieldOffset(10)> <MarshalAs(UnmanagedType.I1)> Dim Data4 As Byte
        <FieldOffset(11)> <MarshalAs(UnmanagedType.I1)> Dim Data5 As Byte
        <FieldOffset(12)> <MarshalAs(UnmanagedType.ByValArray, SizeConst:=2)> Dim Light() As Byte
    End Structure

    Public TileLibLookup() As Integer = {EvoLib.Protocol.ImgLibs.TileSC, _
                                        EvoLib.Protocol.ImgLibs.TileS30C, _
                                        EvoLib.Protocol.ImgLibs.Tiles5C, _
                                        EvoLib.Protocol.ImgLibs.SmTileSC, _
                                        EvoLib.Protocol.ImgLibs.HouseSC, _
                                        EvoLib.Protocol.ImgLibs.CliffSC, _
                                        EvoLib.Protocol.ImgLibs.DungeonSC, _
                                        EvoLib.Protocol.ImgLibs.InnerSC, _
                                        EvoLib.Protocol.ImgLibs.FurnitureSC, _
                                        EvoLib.Protocol.ImgLibs.WallSC, _
                                        EvoLib.Protocol.ImgLibs.SMObjectSC, _
                                        EvoLib.Protocol.ImgLibs.AnimationSC, _
                                            EvoLib.Protocol.ImgLibs.Objects1C, _
                                             EvoLib.Protocol.ImgLibs.Object2C, _
                                             0, _
                                             EvoLib.Protocol.ImgLibs.WoodTileSC, _
                                             0, _
                                             EvoLib.Protocol.ImgLibs.WoodTiles5C, _
                                             0, _
                                             EvoLib.Protocol.ImgLibs.WoodHouseSC, _
                                             EvoLib.Protocol.ImgLibs.WoodCliffSC, _
                                             EvoLib.Protocol.ImgLibs.WoodDungeonSC, _
                                             EvoLib.Protocol.ImgLibs.WoodInnerSC, _
                                        EvoLib.Protocol.ImgLibs.WoodFurnitureSC, _
                                        0, _
                                        EvoLib.Protocol.ImgLibs.WoodSMObjectSC}

    Public Structure LargeTile
        Dim TileSet As Byte
        Dim Index As UInt16
    End Structure

    Public Structure SmallTile
        Dim IsPassable As Boolean
        Dim TopTileSet As Byte
        Dim TopTileIndex As UInt16
        Dim BottomTileSet As Byte
        Dim BottomTileIndex As UInt16
    End Structure

    Public Structure Tile
        Dim TileSet As Byte
        Dim TileIndex As UInt16
    End Structure

    Public Function GetImgLib(ByRef tileset As Byte) As Integer

        Return TileLibLookup(tileset)

    End Function

End Module

Friend Class cMirMapFile

    Public Function GetTile(ByRef x As Integer, ByRef y As Integer) As SmallTile


        If Not IsCoordOnMap(x, y) Then
            Dim tmp As SmallTile
            tmp.TopTileSet = 255
            tmp.TopTileIndex = 65535
            tmp.BottomTileSet = 255
            tmp.BottomTileIndex = 65535
            Return tmp
        End If

        Return mSmallTiles(x, y)

    End Function

    'Public Function GetTopTile(ByRef x As Integer, ByRef y As Integer) As Tile

    'Dim tmp As Tile
    'tmp.TileSet = 255
    'tmp.TileIndex = 65535

    'If Not IsCoordOnMap(x, y) Then
    'Return tmp
    'End If

    'With mSmallTiles(x, y)

    'tmp.TileSet = .TopTileSet
    'tmp.TileIndex = .TopTileIndex
    'End With

    'Return tmp

    'End Function

    Public Function GetLargeTile(ByRef x, ByRef y) As LargeTile

        If Not IsCoordOnMap(x, y) Or x >= mWidth - 2 Or y >= mHeight - 2 Then
            Dim tmp As LargeTile
            tmp.TileSet = 255
            tmp.Index = 65535
            Return tmp
        End If

        Return mLargeTiles(x / 2, y / 2)

    End Function

    Private Function IsCoordOnMap(ByRef x As Integer, ByRef y As Integer) As Boolean

        If x < 0 Or y < 0 Or x >= mWidth Or y >= mHeight Then
            Return False
        Else
            Return True
        End If

    End Function

    Public Function IsPassable(ByRef x As Integer, ByRef y As Integer) As Boolean

        If IsCoordOnMap(x, y) Then
            If mSmallTiles(x, y).IsPassable Then
                Return True
            End If
            Return False
        Else
            Return False
        End If

    End Function

    Public Const sMapPath As String = "F:\MirEvoData\Map\"

    Private mMap As String
    Private mMapFile As String

    Public mWidth As Integer, mHeight As Integer

    Dim mLargeTiles(,) As LargeTile
    Dim mSmallTiles(,) As SmallTile

    Public Sub New(ByRef map As String)

        mMap = map
        mMapFile = Main.sServerPath & "\map\" & map & ".map"

        LoadMapData()

    End Sub

    Private Sub LoadMapData()

        'open the map file
        Dim mapStream As New FileStream(mMapFile, FileMode.Open, FileAccess.Read)
        Dim bBuffer(1) As Byte
        Dim itX As Integer, itY As Integer

        'Skip header bytes
        mapStream.Position = 22

        'read map dimensions
        mapStream.Read(bBuffer, 0, 2)
        mWidth = ArrayToStruct(bBuffer, GetType(UInt16))
        mapStream.Read(bBuffer, 0, 2)
        mHeight = ArrayToStruct(bBuffer, GetType(UInt16))

        'skip 2 bytes, don't know what these do atm, maybe related to tile sets
        mapStream.Position += 2

        '=== LARGE TILES ===

        Dim tmpLargeTile As LargeTile
        Dim buffPos As Integer

        ReDim mLargeTiles((mWidth \ 2) - 1, (mHeight \ 2) - 1)
        ReDim bBuffer(((mWidth \ 2) * (mHeight \ 2) * 3) - 1)

        mapStream.Read(bBuffer, 0, (((mWidth \ 2) * (mHeight \ 2)) * 3))

        For itX = 0 To ((mWidth \ 2) - 1)
            For itY = 0 To ((mHeight \ 2) - 1)

                'create new tile structure
                tmpLargeTile = New LargeTile

                'read the tile into structure
                tmpLargeTile.TileSet = bBuffer(buffPos)
                tmpLargeTile.Index = ArrayToStruct(bBuffer, GetType(UInt16), buffPos + 1)

                'if tile set is invalid set tile index to max
                If tmpLargeTile.TileSet = 255 Then
                    tmpLargeTile.Index = 65535
                Else
                    CheckMissingTileSet(tmpLargeTile.TileSet)
                End If

                '(compatibility) if tile is valid add 1 to the index
                If tmpLargeTile.Index < 65535 Then
                    tmpLargeTile.Index += 1
                End If

                mLargeTiles(itX, itY) = tmpLargeTile
                'preloads tiles
                'If tmpLargeTile.TileSet < 255 Then Libs.GetLib(GetImgLib(tmpLargeTile.TileSet)).Image(tmpLargeTile.Index)


                buffPos += 3

            Next
        Next

        '=== SMALL TILES ===

        ReDim bBuffer(mapStream.Length - mapStream.Position - 1)
        mapStream.Read(bBuffer, 0, (mapStream.Length - mapStream.Position))

        buffPos = 0
        Dim tmpRawSmallTile As RawSmallTile
        Dim tmpSmallTile As SmallTile

        ReDim mSmallTiles(mWidth - 1, mHeight - 1)

        For itX = 0 To mWidth - 1
            For itY = 0 To mHeight - 1

                tmpSmallTile = New SmallTile
                tmpRawSmallTile = ArrayToStruct(bBuffer, GetType(RawSmallTile), buffPos)

                '3 = passable
                If tmpRawSmallTile.passable = 3 Then
                    tmpSmallTile.IsPassable = True
                Else
                    tmpSmallTile.IsPassable = False
                End If

                tmpSmallTile.TopTileSet = tmpRawSmallTile.TopSet
                tmpSmallTile.TopTileIndex = tmpRawSmallTile.TopTile
                If tmpSmallTile.TopTileSet = 255 Then
                    tmpSmallTile.TopTileIndex = 65535
                Else
                    CheckMissingTileSet(tmpRawSmallTile.TopSet)
                End If
                If tmpSmallTile.TopTileIndex < 65535 Then tmpSmallTile.TopTileIndex += 1 ': TileSet(tmp3.TopTileSet).Image(tmp3.TopTileIndex).Precache()

                tmpSmallTile.BottomTileSet = tmpRawSmallTile.BottomSet
                tmpSmallTile.BottomTileIndex = tmpRawSmallTile.BottomTile
                If tmpSmallTile.BottomTileSet = 255 Then
                    tmpSmallTile.BottomTileIndex = 65535
                Else
                    CheckMissingTileSet(tmpRawSmallTile.BottomSet)
                End If
                If tmpSmallTile.BottomTileIndex < 65535 Then tmpSmallTile.BottomTileIndex += 1 ': TileSet(tmp3.BottomTileSet).Image(tmp3.BottomTileIndex).Precache()

                'If tmp3.BottomTileSet <> 255 And tmp3.BottomTileSet <> 0 And tmp3.BottomTileSet <> 10 And tmp3.BottomTileSet <> 23 And tmp3.BottomTileSet <> 4 And tmp3.BottomTileSet <> 5 Then
                '    Debug.Print("###MAP###(" & x.ToString & "," & y.ToString & ") 0x" & Hex(tmp3.BottomTileSet) & " : " & tmp3.BottomTileIndex & "###")
                'End If

                mSmallTiles(itX, itY) = tmpSmallTile
                'preloads tiles
                'If tmpSmallTile.BottomTileSet < 255 Then Libs.GetLib(GetImgLib(tmpSmallTile.BottomTileSet)).Image(tmpSmallTile.BottomTileIndex)
                'If tmpSmallTile.TopTileSet < 255 Then Libs.GetLib(GetImgLib(tmpSmallTile.TopTileSet)).Image(tmpSmallTile.TopTileIndex)

                buffPos += 14

            Next
        Next

        mapStream.Close()

    End Sub

    Private Sub CheckMissingTileSet(ByRef i As Integer)

        Dim missing As Boolean

        If i > TileLibLookup.GetUpperBound(0) Then
            missing = True
        ElseIf TileLibLookup(i) = 0 Then
            missing = True
        End If

        If missing Then
            MsgBox("Missing Tile Set Found! #" & i & " (&H" & Hex(i) & ")")
        End If

    End Sub

End Class
